<?php

namespace Yolo\Config\Annotations;

use Attribute;
use ReflectionException;
use Yolo\Components\Validator\ValidatorFactory;
use Yolo\Di\DI;
use Yolo\Di\Errors\CircularDependencyException;
use Yolo\Di\Errors\InvalidAttributeException;
use Yolo\Di\Errors\ParameterTypeEmptyException;
use Yolo\Di\PropertyAttributeInterface;
use Yolo\Errors\InvalidConfigValueException;
use Yolo\Service\ApplicationContainer;

/**
 * 配置注解
 * @author <LUSHAOMING> <lushaoming6@gmail.com>
 * @date 2024-12-06
 */
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_PARAMETER)]
class UseConfig implements PropertyAttributeInterface
{
    /**
     * 配置注解
     * @param string $path 配置路径
     * @param array|string $validations 验证规则
     */
    public function __construct(
        private readonly string $path,
        private readonly array|string $validations = []
    ){}

    /**
     * @return mixed
     * @throws InvalidConfigValueException
     * @throws ReflectionException
     * @throws CircularDependencyException
     * @throws InvalidAttributeException
     * @throws ParameterTypeEmptyException
     */
    public function inject(): mixed
    {
        $container = DI::use(ApplicationContainer::class);
        $validator = DI::use(ValidatorFactory::class);
        $config = $container->getConfig()->get($this->path);

        if (empty($this->validations)) {
            return $config;
        }

        $messageBag = null;
        if (is_array($this->validations)) {

            $messageBag = $validator->validate($this->validations, $config);
        } elseif (is_string($this->validations)) {

            if (str_starts_with($this->validations, '@')) {
                $messageBag = $validator->validate($this->validations, $config);
            } else {
                $messageBag = $validator->validate(['config' => $this->validations], ['config' => $config]);
            }
        }

        if ($messageBag) {

            $ex = new InvalidConfigValueException("Invalid config value for $this->path\nvalidations: " . (is_string($this->validations) ? $this->validations : json_encode($this->validations, JSON_PRETTY_PRINT)));
            $ex->setErrors($messageBag);
            throw $ex;
        }

        return $config;
    }
}
